package com.crud.generator.controller;

import com.crud.generator.common.ApiResponse;
import com.crud.generator.dto.BatchDatabaseRequest;
import com.crud.generator.dto.BatchGenerationRequest;
import com.crud.generator.dto.DatabaseConnectionRequest;
import com.crud.generator.dto.SqlParseRequest;
import com.crud.generator.exception.CodeGenerationException;
import com.crud.generator.exception.SqlParseException;
import com.crud.generator.generator.CrudGenerator;
import com.crud.generator.generator.GenerationOptions;
import com.crud.generator.model.ColumnMetadata;
import com.crud.generator.model.TableMetadata;
import com.crud.generator.parser.SqlDdlParser;
import com.crud.generator.service.DatabaseReverseService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成控制器
 * 
 * @author CRUD-Generator
 */
@RestController
@RequestMapping("/api/generator")
@Tag(name = "智能CRUD代码生成器", description = "基于SQL DDL自动生成CRUD代码的API接口")
@Slf4j
public class GeneratorController {

    @Autowired
    private SqlDdlParser sqlDdlParser;
    
    @Autowired
    private CrudGenerator crudGenerator;
    
    @Autowired
    private DatabaseReverseService databaseReverseService;
    
    /** 危险SQL关键字 */
    private static final List<String> DANGEROUS_KEYWORDS = Arrays.asList(
        "DROP", "DELETE", "TRUNCATE", "ALTER", "UPDATE", "INSERT"
    );

    /**
     * 解析SQL DDL语句
     */
    @PostMapping("/parse-sql")
    @Operation(
        summary = "解析SQL DDL语句",
        description = "解析CREATE TABLE语句，提取表结构信息，支持MySQL语法"
    )
    public ResponseEntity<ApiResponse<TableMetadata>> parseSql(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到SQL解析请求，表名模式检测中...");
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(request.getDdl().trim());
            
            log.info("SQL解析成功: 表名={}, 字段数={}", 
                tableMetadata.getTableName(), 
                tableMetadata.getColumns().size());
            
            return ResponseEntity.ok(ApiResponse.success(tableMetadata, "SQL解析成功"));
            
        } catch (Exception e) {
            log.error("SQL解析失败: {}", e.getMessage());
            throw new SqlParseException("SQL语法错误，请检查CREATE TABLE语句格式");
        }
    }
    
    /**
     * 解析多个SQL DDL语句
     */
    @PostMapping("/parse-multiple-sql")
    @Operation(
        summary = "解析多个SQL DDL语句",
        description = "解析包含多个CREATE TABLE语句的DDL，返回所有表的结构信息"
    )
    public ResponseEntity<ApiResponse<List<TableMetadata>>> parseMultipleSql(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到多表SQL解析请求...");
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            List<TableMetadata> tables = sqlDdlParser.parseMultipleCreateTable(request.getDdl().trim());
            
            log.info("多表SQL解析成功: 解析了{}个表", tables.size());
            
            return ResponseEntity.ok(ApiResponse.success(tables, "多表SQL解析成功"));
            
        } catch (Exception e) {
            log.error("多表SQL解析失败: {}", e.getMessage());
            throw new SqlParseException("SQL语法错误，请检查CREATE TABLE语句格式");
        }
    }

    /**
     * 预览生成的代码
     */
    @PostMapping("/preview-code")
    @Operation(
        summary = "预览生成的代码",
        description = "在实际生成前预览代码内容，支持语法高亮"
    )
    public ResponseEntity<ApiResponse<Map<String, String>>> previewCode(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到代码预览请求");
        
        // 验证请求参数格式
        validateRequest(request);
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(request.getDdl().trim());
            
            // 设置自定义配置
            if (request.getPackagePrefix() != null) {
                // 这里可以设置自定义包名
            }
            if (request.getAuthor() != null) {
                // 这里可以设置自定义作者
            }
            
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            Map<String, String> codePreview = crudGenerator.previewAll(tableMetadata, options);
            
            log.info("代码预览生成成功: 表名={}", tableMetadata.getTableName());
            
            return ResponseEntity.ok(ApiResponse.success(codePreview, "代码预览生成成功"));
            
        } catch (Exception e) {
            log.error("代码预览失败: {}", e.getMessage());
            throw new CodeGenerationException("代码预览失败: " + e.getMessage());
        }
    }

    /**
     * 生成CRUD代码
     */
    @PostMapping("/generate-code")
    @Operation(
        summary = "生成CRUD代码",
        description = "根据SQL DDL生成完整的CRUD代码文件"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> generateCode(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到代码生成请求");
        
        // 验证请求参数格式
        validateRequest(request);
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(request.getDdl().trim());
            
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            // 获取代码预览内容
            Map<String, String> codePreview = crudGenerator.previewAll(tableMetadata, options);
            
            // 构建响应数据
            Map<String, Object> result = new HashMap<>();
            result.put("tableName", tableMetadata.getTableName());
            result.put("entityName", toPascalCase(tableMetadata.getTableName()));
            result.put("columnCount", tableMetadata.getColumns().size());
            result.put("hasAutoIncrement", tableMetadata.getPrimaryKey() != null && 
                Boolean.TRUE.equals(tableMetadata.getPrimaryKey().getAutoIncrement()));
            
            // 构建文件映射，前端期望的格式
            Map<String, String> files = new HashMap<>();
            String entityName = toPascalCase(tableMetadata.getTableName());
            files.put(entityName + ".java", codePreview.get("entity"));
            files.put(entityName + "Repository.java", codePreview.get("repository"));
            files.put(entityName + "Service.java", codePreview.get("service"));
            files.put(entityName + "Controller.java", codePreview.get("controller"));
            
            result.put("files", files);
            
            log.info("代码生成成功: 表名={}, 字段数={}", 
                tableMetadata.getTableName(), 
                tableMetadata.getColumns().size());
            
            return ResponseEntity.ok(ApiResponse.success(result, "代码生成成功"));
            
        } catch (Exception e) {
            log.error("代码生成失败: {}", e.getMessage());
            throw new CodeGenerationException("代码生成失败: " + e.getMessage());
        }
    }

    /**
     * 生成多表CRUD代码
     */
    @PostMapping("/generate-multiple-code")
    @Operation(
        summary = "生成多表CRUD代码",
        description = "根据包含多个CREATE TABLE的SQL DDL生成完整的CRUD代码文件"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> generateMultipleCode(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到多表代码生成请求");
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            List<TableMetadata> tables = sqlDdlParser.parseMultipleCreateTable(request.getDdl().trim());
            
            if (tables.isEmpty()) {
                throw new CodeGenerationException("未找到有效的CREATE TABLE语句");
            }
            
            // 构建响应数据
            Map<String, Object> result = new HashMap<>();
            Map<String, String> allFiles = new HashMap<>();
            List<Map<String, Object>> tableInfos = new ArrayList<>();
            
            int totalFiles = 0;
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            
            for (TableMetadata tableMetadata : tables) {
                try {
                    // 获取代码预览内容
                    Map<String, String> codePreview = crudGenerator.previewAll(tableMetadata, options);
                    
                    String entityName = toPascalCase(tableMetadata.getTableName());
                    
                    // 添加到总文件映射中
                    allFiles.put(entityName + ".java", codePreview.get("entity"));
                    allFiles.put(entityName + "Repository.java", codePreview.get("repository"));
                    allFiles.put(entityName + "Service.java", codePreview.get("service"));
                    allFiles.put(entityName + "Controller.java", codePreview.get("controller"));
                    
                    totalFiles += 4;
                    
                    // 添加表信息
                    Map<String, Object> tableInfo = new HashMap<>();
                    tableInfo.put("tableName", tableMetadata.getTableName());
                    tableInfo.put("entityName", entityName);
                    tableInfo.put("columnCount", tableMetadata.getColumns().size());
                    tableInfo.put("hasAutoIncrement", tableMetadata.getPrimaryKey() != null && 
                        Boolean.TRUE.equals(tableMetadata.getPrimaryKey().getAutoIncrement()));
                    tableInfos.add(tableInfo);
                    
                    log.info("表 {} 代码生成成功，字段数: {}", tableMetadata.getTableName(), tableMetadata.getColumns().size());
                    
                } catch (Exception e) {
                    log.warn("表 {} 代码生成失败: {}", tableMetadata.getTableName(), e.getMessage());
                    // 继续处理其他表，不中断整个流程
                }
            }
            
            result.put("files", allFiles);
            result.put("tables", tableInfos);
            result.put("totalTables", tables.size());
            result.put("totalFiles", totalFiles);
            result.put("successTables", tableInfos.size());
            
            log.info("多表代码生成完成: 总表数={}, 成功生成={}, 总文件数={}", 
                tables.size(), tableInfos.size(), totalFiles);
            
            return ResponseEntity.ok(ApiResponse.success(result, 
                String.format("多表代码生成成功！已生成 %d 个表的代码，共 %d 个文件", tableInfos.size(), totalFiles)));
            
        } catch (Exception e) {
            log.error("多表代码生成失败: {}", e.getMessage());
            throw new CodeGenerationException("多表代码生成失败: " + e.getMessage());
        }
    }

    /**
     * 验证SQL语法
     */
    @PostMapping("/validate-sql")
    @Operation(
        summary = "验证SQL语法",
        description = "验证SQL DDL语法是否正确，不执行实际解析"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> validateSql(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到SQL语法验证请求");
        
        try {
            // 验证请求参数格式
            validateRequest(request);
            
            // SQL安全检查
            validateSqlSafety(request.getDdl());
            
            // 尝试解析SQL
            TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(request.getDdl().trim());
            
            Map<String, Object> result = new HashMap<>();
            result.put("valid", true);
            result.put("tableName", tableMetadata.getTableName());
            result.put("columnCount", tableMetadata.getColumns().size());
            result.put("hasPrimaryKey", tableMetadata.getPrimaryKey() != null);
            
            return ResponseEntity.ok(ApiResponse.success(result, "SQL语法验证通过"));
            
        } catch (Exception e) {
            log.warn("SQL语法验证失败: {}", e.getMessage());
            
            Map<String, Object> result = new HashMap<>();
            result.put("valid", false);
            result.put("error", e.getMessage());
            
            return ResponseEntity.ok(ApiResponse.success(result, "SQL语法验证失败"));
        }
    }
    
    /**
     * 下载多表代码包
     */
    @PostMapping("/download-multiple-code")
    @Operation(
        summary = "下载多表代码包",
        description = "将生成的多表CRUD代码打包为ZIP文件下载"
    )
    public ResponseEntity<ByteArrayResource> downloadMultipleCode(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到多表代码下载请求");
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            List<TableMetadata> tableMetadataList = sqlDdlParser.parseMultipleCreateTable(request.getDdl().trim());
            
            if (tableMetadataList.isEmpty()) {
                throw new CodeGenerationException("未找到有效的CREATE TABLE语句");
            }
            
            // 创建ZIP文件
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);
            
            String packagePath = (request.getPackagePrefix() != null ? request.getPackagePrefix() : "com.example").replace(".", "/");
            int totalFiles = 0;
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            Map<String, String> sharedPreview = null;
            
            // 为每个表生成代码文件
            for (TableMetadata tableMetadata : tableMetadataList) {
                try {
                    // 获取代码预览内容
                    Map<String, String> codePreview = crudGenerator.previewAll(tableMetadata, options);
                    if (sharedPreview == null) {
                        sharedPreview = codePreview;
                    }
                    String entityName = toPascalCase(tableMetadata.getTableName());
                    
                    // 添加Entity文件
                    addFileToZip(zos, "src/main/java/" + packagePath + "/entity/" + entityName + ".java", codePreview.get("entity"));
                    
                    // 添加Mapper文件
                    addFileToZip(zos, "src/main/java/" + packagePath + "/mapper/" + entityName + "Mapper.java", codePreview.get("repository"));
                    
                    // 添加Service文件
                    addFileToZip(zos, "src/main/java/" + packagePath + "/service/" + entityName + "Service.java", codePreview.get("service"));
                    
                    // 添加Controller文件
                    addFileToZip(zos, "src/main/java/" + packagePath + "/controller/" + entityName + "Controller.java", codePreview.get("controller"));
                    
                    totalFiles += 4;
                    log.info("表 {} 的代码文件已添加到ZIP包", tableMetadata.getTableName());
                    
                } catch (Exception e) {
                    log.warn("表 {} 代码生成失败，跳过: {}", tableMetadata.getTableName(), e.getMessage());
                }
            }
            
            if (sharedPreview != null) {
                if (options.isEnableSecurity()) {
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/controller/AuthController.java", sharedPreview.get("authController"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/config/SecurityConfig.java", sharedPreview.get("securityConfig"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/config/TenantSecurityProperties.java", sharedPreview.get("tenantSecurityProperties"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/config/MybatisTenantConfig.java", sharedPreview.get("mybatisTenantConfig"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtAuthenticationEntryPoint.java", sharedPreview.get("jwtAuthenticationEntryPoint"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtAuthenticationFilter.java", sharedPreview.get("jwtAuthenticationFilter"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtTokenProvider.java", sharedPreview.get("jwtTokenProvider"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/security/TenantAuthenticationService.java", sharedPreview.get("tenantAuthenticationService"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantContext.java", sharedPreview.get("tenantContext"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantFilter.java", sharedPreview.get("tenantFilter"));
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantLineHandlerImpl.java", sharedPreview.get("tenantLineHandler"));
                }
                if (options.isEnableRedis()) {
                    addOptionalFile(zos, "src/main/java/" + packagePath + "/config/RedisConfig.java", sharedPreview.get("redisConfig"));
                }
            }

            // 添加公共文件
            String projectName = "multi-table-crud";
            
            // 添加pom.xml文件
            String pomContent = generateMultiTablePomContent(projectName, request.getPackagePrefix());
            addFileToZip(zos, "pom.xml", pomContent);
            
            // 添加application.yml文件
            String ymlContent = generateApplicationYmlContent(projectName);
            addFileToZip(zos, "src/main/resources/application.yml", ymlContent);
            
            // 添加启动类
            String mainClassContent = generateMainClassContent("MultiTable", request.getPackagePrefix());
            addFileToZip(zos, "src/main/java/" + packagePath + "/MultiTableApplication.java", mainClassContent);
            
            // 添加README文件
            String readmeContent = generateMultiTableReadmeContent(tableMetadataList, request.getPackagePrefix());
            addFileToZip(zos, "README.md", readmeContent);
            
            totalFiles += 4;
            
            zos.close();
            
            ByteArrayResource resource = new ByteArrayResource(baos.toByteArray());
            
            String fileName = "multi-table-crud-code.zip";
            
            log.info("多表代码下载包生成成功: 文件名={}, 表数={}, 总文件数={}, 大小={}KB", 
                    fileName, tableMetadataList.size(), totalFiles, baos.size() / 1024);
            
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(resource.contentLength())
                    .body(resource);
            
        } catch (Exception e) {
            log.error("多表代码下载失败: {}", e.getMessage());
            throw new CodeGenerationException("多表代码下载失败: " + e.getMessage());
        }
    }
    
    /**
     * 下载代码包
     */
    @PostMapping("/download-code")
    @Operation(
        summary = "下载代码包",
        description = "将生成的CRUD代码打包为ZIP文件下载"
    )
    public ResponseEntity<ByteArrayResource> downloadCode(
            @Parameter(description = "SQL解析请求") @RequestBody @Valid SqlParseRequest request) {
        
        log.info("收到代码下载请求");
        
        // 验证请求参数格式
        validateRequest(request);
        
        // SQL安全检查
        validateSqlSafety(request.getDdl());
        
        try {
            TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(request.getDdl().trim());
            
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());

            // 创建临时目录用于生成文件
            String tempDir = System.getProperty("java.io.tmpdir") + File.separator + "crud-generator-" + System.currentTimeMillis();
            File tempDirFile = new File(tempDir);
            tempDirFile.mkdirs();
            
            // 设置输出路径并生成所有文件
            crudGenerator.setOutputPath(tempDir);
            crudGenerator.generateAll(tableMetadata, options);
            
            // 获取代码预览内容（用于后端文件）
            Map<String, String> codePreview = crudGenerator.previewAll(tableMetadata, options);
            
            // 创建ZIP文件
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ZipOutputStream zos = new ZipOutputStream(baos);
            
            String entityName = toPascalCase(tableMetadata.getTableName());
            String packagePath = (request.getPackagePrefix() != null ? request.getPackagePrefix() : "com.example").replace(".", "/");
            
            // 添加后端文件
            addFileToZip(zos, "src/main/java/" + packagePath + "/entity/" + entityName + ".java", codePreview.get("entity"));
            addFileToZip(zos, "src/main/java/" + packagePath + "/mapper/" + entityName + "Mapper.java", codePreview.get("repository"));
            addFileToZip(zos, "src/main/java/" + packagePath + "/service/" + entityName + "Service.java", codePreview.get("service"));
            addFileToZip(zos, "src/main/java/" + packagePath + "/controller/" + entityName + "Controller.java", codePreview.get("controller"));

            if (options.isEnableSecurity()) {
                addOptionalFile(zos, "src/main/java/" + packagePath + "/controller/AuthController.java", codePreview.get("authController"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/config/SecurityConfig.java", codePreview.get("securityConfig"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/config/TenantSecurityProperties.java", codePreview.get("tenantSecurityProperties"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/config/MybatisTenantConfig.java", codePreview.get("mybatisTenantConfig"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtAuthenticationEntryPoint.java", codePreview.get("jwtAuthenticationEntryPoint"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtAuthenticationFilter.java", codePreview.get("jwtAuthenticationFilter"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/security/JwtTokenProvider.java", codePreview.get("jwtTokenProvider"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/security/TenantAuthenticationService.java", codePreview.get("tenantAuthenticationService"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantContext.java", codePreview.get("tenantContext"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantFilter.java", codePreview.get("tenantFilter"));
                addOptionalFile(zos, "src/main/java/" + packagePath + "/tenant/TenantLineHandlerImpl.java", codePreview.get("tenantLineHandler"));
            }

            if (options.isEnableRedis()) {
                addOptionalFile(zos, "src/main/java/" + packagePath + "/config/RedisConfig.java", codePreview.get("redisConfig"));
            }
            
            // 添加后端配置文件
            String pomContent = generatePomContent(entityName, request.getPackagePrefix());
            addFileToZip(zos, "pom.xml", pomContent);
            
            String ymlContent = generateApplicationYmlContent(entityName);
            addFileToZip(zos, "src/main/resources/application.yml", ymlContent);
            
            String mainClassContent = generateMainClassContent(entityName, request.getPackagePrefix());
            addFileToZip(zos, "src/main/java/" + packagePath + "/" + entityName + "Application.java", mainClassContent);
            
            String readmeContent = generateReadmeContent(tableMetadata, entityName, request.getPackagePrefix());
            addFileToZip(zos, "README.md", readmeContent);
            
            // 添加前端文件
            String frontendBasePath = tempDir + File.separator + entityName.toLowerCase() + File.separator + "frontend";
            addFrontendFilesToZip(zos, frontendBasePath, "frontend");
            
            zos.close();
            
            // 清理临时目录
            deleteDirectory(tempDirFile);
            
            ByteArrayResource resource = new ByteArrayResource(baos.toByteArray());
            
            String fileName = entityName.toLowerCase() + "-crud-code.zip";
            
            log.info("代码下载包生成成功: 文件名={}, 大小={}KB", fileName, baos.size() / 1024);
            
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(resource.contentLength())
                    .body(resource);
            
        } catch (Exception e) {
            log.error("代码下载失败: {}", e.getMessage());
            throw new CodeGenerationException("代码下载失败: " + e.getMessage());
        }
    }
    
    /**
     * 添加文件到ZIP
     */
    private void addFileToZip(ZipOutputStream zos, String fileName, String content) throws IOException {
        ZipEntry entry = new ZipEntry(fileName);
        zos.putNextEntry(entry);
        zos.write(content.getBytes(StandardCharsets.UTF_8));
        zos.closeEntry();
    }

    private void addOptionalFile(ZipOutputStream zos, String fileName, String content) throws IOException {
        if (content == null || content.isEmpty()) {
            return;
        }
        addFileToZip(zos, fileName, content);
    }
    
    /**
     * 添加前端文件到ZIP
     */
    private void addFrontendFilesToZip(ZipOutputStream zos, String frontendBasePath, String zipBasePath) throws IOException {
        File frontendDir = new File(frontendBasePath);
        if (frontendDir.exists() && frontendDir.isDirectory()) {
            addDirectoryToZip(zos, frontendDir, zipBasePath);
        }
    }
    
    /**
     * 递归添加目录到ZIP
     */
    private void addDirectoryToZip(ZipOutputStream zos, File directory, String zipBasePath) throws IOException {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                String zipPath = zipBasePath + "/" + file.getName();
                if (file.isDirectory()) {
                    addDirectoryToZip(zos, file, zipPath);
                } else {
                    try (FileInputStream fis = new FileInputStream(file)) {
                        ZipEntry entry = new ZipEntry(zipPath);
                        zos.putNextEntry(entry);
                        
                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = fis.read(buffer)) > 0) {
                            zos.write(buffer, 0, length);
                        }
                        zos.closeEntry();
                    }
                }
            }
        }
    }
    
    /**
     * 删除目录及其所有内容
     */
    private void deleteDirectory(File directory) {
        if (directory.exists()) {
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (file.isDirectory()) {
                        deleteDirectory(file);
                    } else {
                        file.delete();
                    }
                }
            }
            directory.delete();
        }
    }
    
    /**
     * 生成README内容
     */
    private String generateReadmeContent(TableMetadata tableMetadata, String entityName, String packagePrefix) {
        StringBuilder readme = new StringBuilder();
        readme.append("# ").append(entityName).append(" CRUD代码\n\n");
        readme.append("## 项目信息\n");
        readme.append("- **表名**: ").append(tableMetadata.getTableName()).append("\n");
        readme.append("- **实体类**: ").append(entityName).append("\n");
        readme.append("- **包名**: ").append(packagePrefix != null ? packagePrefix : "com.example").append("\n");
        readme.append("- **字段数量**: ").append(tableMetadata.getColumns().size()).append("\n");
        readme.append("- **生成时间**: ").append(java.time.LocalDateTime.now().toString()).append("\n\n");
        
        readme.append("## 文件结构\n");
        readme.append("```\n");
        readme.append("├── pom.xml\n");
        readme.append("├── README.md\n");
        readme.append("└── src/\n");
        readme.append("    └── main/\n");
        readme.append("        ├── java/\n");
        String packagePath = (packagePrefix != null ? packagePrefix : "com.example").replace(".", "/");
        readme.append("        |   └── ").append(packagePath).append("/\n");
        readme.append("        |       ├── ").append(entityName).append("Application.java\n");
        readme.append("        |       ├── entity/\n");
        readme.append("        |       |   └── ").append(entityName).append(".java\n");
        readme.append("        |       ├── mapper/\n");
        readme.append("        |       |   └── ").append(entityName).append("Mapper.java\n");
        readme.append("        |       ├── service/\n");
        readme.append("        |       |   └── ").append(entityName).append("Service.java\n");
        readme.append("        |       └── controller/\n");
        readme.append("        |           └── ").append(entityName).append("Controller.java\n");
        readme.append("        └── resources/\n");
        readme.append("            └── application.yml\n");
        readme.append("```\n\n");
        
        readme.append("## 使用说明\n");
        readme.append("### 1. 环境要求\n");
        readme.append("- Java 8+\n");
        readme.append("- Maven 3.6+\n");
        readme.append("- MySQL 5.7+\n\n");
        readme.append("### 2. 数据库准备\n");
        readme.append("创建数据库并执行以下SQL：\n");
        readme.append("```sql\n");
        readme.append("CREATE DATABASE ").append(entityName.toLowerCase()).append("_db;\n");
        readme.append("USE ").append(entityName.toLowerCase()).append("_db;\n");
        readme.append("-- 这里放入你的CREATE TABLE语句\n");
        readme.append("```\n\n");
        readme.append("### 3. 配置修改\n");
        readme.append("根据实际情况修改 `src/main/resources/application.yml` 中的数据库连接信息：\n");
        readme.append("- 数据库URL\n");
        readme.append("- 用户名和密码\n\n");
        readme.append("### 4. 运行项目\n");
        readme.append("```bash\n");
        readme.append("# 编译项目\n");
        readme.append("mvn clean compile\n\n");
        readme.append("# 运行项目\n");
        readme.append("mvn spring-boot:run\n");
        readme.append("```\n\n");
        readme.append("### 5. 访问应用\n");
        readme.append("- 应用地址：http://localhost:8080\n");
        readme.append("- API文档：http://localhost:8080/swagger-ui.html\n\n");
        
        readme.append("## API接口\n");
        String tableName = tableMetadata.getTableName().toLowerCase();
        readme.append("- `POST /api/").append(tableName).append("` - 创建记录\n");
        readme.append("- `GET /api/").append(tableName).append("/{id}` - 根据ID查询\n");
        readme.append("- `GET /api/").append(tableName).append("` - \u67e5\u8be2\u6240\u6709\u8bb0\u5f55\n");
        readme.append("- `GET /api/").append(tableName).append("/page` - 分页查询\n");
        readme.append("- `PUT /api/").append(tableName).append("/{id}` - 更新记录\n");
        readme.append("- `DELETE /api/").append(tableName).append("/{id}` - 删除记录\n\n");
        
        readme.append("---\n");
        readme.append("*此代码由 CRUD Generator 自动生成*\n");
        
        return readme.toString();
    }
    
    /**
     * 生成pom.xml内容
     */
    private String generatePomContent(String entityName, String packagePrefix) {
        String groupId = packagePrefix != null ? packagePrefix : "com.example";
        String artifactId = entityName.toLowerCase() + "-crud";
        
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
                "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
                "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 \n" +
                "         http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
                "    <modelVersion>4.0.0</modelVersion>\n\n" +
                "    <groupId>" + groupId + "</groupId>\n" +
                "    <artifactId>" + artifactId + "</artifactId>\n" +
                "    <version>1.0.0</version>\n" +
                "    <packaging>jar</packaging>\n\n" +
                "    <name>" + entityName + " CRUD</name>\n" +
                "    <description>" + entityName + " CRUD项目</description>\n\n" +
                "    <parent>\n" +
                "        <groupId>org.springframework.boot</groupId>\n" +
                "        <artifactId>spring-boot-starter-parent</artifactId>\n" +
                "        <version>2.7.18</version>\n" +
                "        <relativePath/>\n" +
                "    </parent>\n\n" +
                "    <properties>\n" +
                "        <java.version>8</java.version>\n" +
                "        <maven.compiler.source>8</maven.compiler.source>\n" +
                "        <maven.compiler.target>8</maven.compiler.target>\n" +
                "        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n" +
                "    </properties>\n\n" +
                "    <dependencies>\n" +
                "        <!-- Spring Boot Starter Web -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springframework.boot</groupId>\n" +
                "            <artifactId>spring-boot-starter-web</artifactId>\n" +
                "        </dependency>\n\n" +
                "        <!-- MyBatis-Plus Starter -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.baomidou</groupId>\n" +
                "            <artifactId>mybatis-plus-boot-starter</artifactId>\n" +
                "            <version>3.5.3.1</version>\n" +
                "        </dependency>\n\n" +
                "        <!-- Spring Boot Starter Validation -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springframework.boot</groupId>\n" +
                "            <artifactId>spring-boot-starter-validation</artifactId>\n" +
                "        </dependency>\n\n" +
                "        <!-- MySQL Connector -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.mysql</groupId>\n" +
                "            <artifactId>mysql-connector-j</artifactId>\n" +
                "            <scope>runtime</scope>\n" +
                "        </dependency>\n\n" +
                "        <!-- Swagger OpenAPI -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springdoc</groupId>\n" +
                "            <artifactId>springdoc-openapi-ui</artifactId>\n" +
                "            <version>1.7.0</version>\n" +
                "        </dependency>\n\n" +
                "        <!-- Apache Commons Lang3 -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.apache.commons</groupId>\n" +
                "            <artifactId>commons-lang3</artifactId>\n" +
                "        </dependency>\n\n" +
                "        <!-- Jackson for JSON processing -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.fasterxml.jackson.core</groupId>\n" +
                "            <artifactId>jackson-databind</artifactId>\n" +
                "        </dependency>\n\n" +
                "        <!-- Lombok -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.projectlombok</groupId>\n" +
                "            <artifactId>lombok</artifactId>\n" +
                "            <optional>true</optional>\n" +
                "        </dependency>\n\n" +
                "        <!-- Spring Boot Test -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springframework.boot</groupId>\n" +
                "            <artifactId>spring-boot-starter-test</artifactId>\n" +
                "            <scope>test</scope>\n" +
                "        </dependency>\n\n" +
                "        <!-- H2 Database for Testing -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.h2database</groupId>\n" +
                "            <artifactId>h2</artifactId>\n" +
                "            <scope>test</scope>\n" +
                "        </dependency>\n" +
                "    </dependencies>\n\n" +
                "    <build>\n" +
                "        <plugins>\n" +
                "            <plugin>\n" +
                "                <groupId>org.springframework.boot</groupId>\n" +
                "                <artifactId>spring-boot-maven-plugin</artifactId>\n" +
                "                <configuration>\n" +
                "                    <excludes>\n" +
                "                        <exclude>\n" +
                "                            <groupId>org.projectlombok</groupId>\n" +
                "                            <artifactId>lombok</artifactId>\n" +
                "                        </exclude>\n" +
                "                    </excludes>\n" +
                "                </configuration>\n" +
                "            </plugin>\n\n" +
                "            <!-- Maven Compiler Plugin -->\n" +
                "            <plugin>\n" +
                "                <groupId>org.apache.maven.plugins</groupId>\n" +
                "                <artifactId>maven-compiler-plugin</artifactId>\n" +
                "                <version>3.11.0</version>\n" +
                "                <configuration>\n" +
                "                    <source>8</source>\n" +
                "                    <target>8</target>\n" +
                "                </configuration>\n" +
                "            </plugin>\n" +
                "        </plugins>\n" +
                "    </build>\n\n" +
                "    <repositories>\n" +
                "        <repository>\n" +
                "            <id>maven.aliyun.com</id>\n" +
                "            <name>阿里云Maven仓库</name>\n" +
                "            <url>https://maven.aliyun.com/repository/public</url>\n" +
                "        </repository>\n" +
                "    </repositories>\n" +
                "</project>\n";
    }
    
    /**
     * 生成application.yml内容
     */
    private String generateApplicationYmlContent(String entityName) {
        String tableName = entityName.toLowerCase();
        
        return "spring:\n" +
                "  application:\n" +
                "    name: " + tableName + "-crud\n\n" +
                "  # 数据库配置\n" +
                "  datasource:\n" +
                "    url: jdbc:mysql://localhost:3306/" + tableName + "_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai\n" +
                "    username: root\n" +
                "    password: 123456\n" +
                "    driver-class-name: com.mysql.cj.jdbc.Driver\n\n" +
                "\n# MyBatis-Plus配置\n" +
                "mybatis-plus:\n" +
                "  configuration:\n" +
                "    map-underscore-to-camel-case: true\n" +
                "    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\n" +
                "  global-config:\n" +
                "    db-config:\n" +
                "      id-type: auto\n" +
                "      logic-delete-field: deleted\n" +
                "      logic-delete-value: 1\n" +
                "      logic-not-delete-value: 0\n" +
                "  mapper-locations: classpath*:/mapper/**/*.xml\n\n" +
                "# 服务器配置\n" +
                "server:\n" +
                "  port: 8080\n" +
                "  servlet:\n" +
                "    context-path: /\n" +
                "    encoding:\n" +
                "      charset: UTF-8\n" +
                "      enabled: true\n" +
                "      force: true\n\n" +
                "# Swagger配置\n" +
                "springdoc:\n" +
                "  api-docs:\n" +
                "    enabled: true\n" +
                "    path: /v3/api-docs\n" +
                "  swagger-ui:\n" +
                "    enabled: true\n" +
                "    path: /swagger-ui.html\n" +
                "    tags-sorter: alpha\n" +
                "    operations-sorter: alpha\n\n" +
                "# 日志配置\n" +
                "logging:\n" +
                "  level:\n" +
                "    com." + (entityName.toLowerCase()) + ": DEBUG\n" +
                "    org.springframework.web: INFO\n" +
                "  pattern:\n" +
                "    console: \"%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n\"\n";
    }
    
    /**
     * Generate main class content
     */
    private String generateMainClassContent(String entityName, String packagePrefix) {
        String packageName = packagePrefix != null ? packagePrefix : "com.example";
        
        return "package " + packageName + ";\n\n" +
                "import org.springframework.boot.SpringApplication;\n" +
                "import org.springframework.boot.autoconfigure.SpringBootApplication;\n" +
                "import org.mybatis.spring.annotation.MapperScan;\n" +
                "import io.swagger.v3.oas.annotations.OpenAPIDefinition;\n" +
                "import io.swagger.v3.oas.annotations.info.Info;\n\n" +
                "/**\n" +
                " * " + entityName + " CRUD应用启动类\n" +
                " * \n" +
                " * @author CRUD-Generator\n" +
                " */\n" +
                "@SpringBootApplication\n" +
                "@MapperScan(\"" + packageName + ".mapper\")\n" +
                "@OpenAPIDefinition(\n" +
                "    info = @Info(\n" +
                "        title = \"" + entityName + " CRUD API\",\n" +
                "        description = \"" + entityName + " CRUD接口文档\",\n" +
                "        version = \"1.0.0\"\n" +
                "    )\n" +
                ")\n" +
                "public class " + entityName + "Application {\n\n" +
                "    public static void main(String[] args) {\n" +
                "        SpringApplication.run(" + entityName + "Application.class, args);\n" +
                "    }\n" +
                "}\n";
    }
    
    /**
     * 转换为PascalCase
     */
    private String toPascalCase(String str) {
        if (str == null || str.trim().isEmpty()) {
            return str;
        }
        
        StringBuilder result = new StringBuilder();
        boolean toUpper = true;
        
        for (char c : str.toCharArray()) {
            if (c == '_') {
                toUpper = true;
            } else {
                if (toUpper) {
                    result.append(Character.toUpperCase(c));
                    toUpper = false;
                } else {
                    result.append(Character.toLowerCase(c));
                }
            }
        }
        
        return result.toString();
    }
    
    /**
     * 生成多表项目的pom.xml内容
     */
    private String generateMultiTablePomContent(String projectName, String packagePrefix) {
        String groupId = packagePrefix != null ? packagePrefix : "com.example";
        String artifactId = projectName;
        
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
                "         xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
                "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 \n" +
                "         http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
                "    <modelVersion>4.0.0</modelVersion>\n\n" +
                "    <groupId>" + groupId + "</groupId>\n" +
                "    <artifactId>" + artifactId + "</artifactId>\n" +
                "    <version>1.0.0</version>\n" +
                "    <packaging>jar</packaging>\n\n" +
                "    <name>Multi-Table CRUD</name>\n" +
                "    <description>多表CRUD项目</description>\n\n" +
                "    <parent>\n" +
                "        <groupId>org.springframework.boot</groupId>\n" +
                "        <artifactId>spring-boot-starter-parent</artifactId>\n" +
                "        <version>2.7.18</version>\n" +
                "        <relativePath/>\n" +
                "    </parent>\n\n" +
                "    <properties>\n" +
                "        <java.version>8</java.version>\n" +
                "        <maven.compiler.source>8</maven.compiler.source>\n" +
                "        <maven.compiler.target>8</maven.compiler.target>\n" +
                "        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n" +
                "    </properties>\n\n" +
                "    <dependencies>\n" +
                "        <!-- Spring Boot Web Starter -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springframework.boot</groupId>\n" +
                "            <artifactId>spring-boot-starter-web</artifactId>\n" +
                "        </dependency>\n\n" +
                "        <!-- MyBatis-Plus -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.baomidou</groupId>\n" +
                "            <artifactId>mybatis-plus-boot-starter</artifactId>\n" +
                "            <version>3.5.3.1</version>\n" +
                "        </dependency>\n\n" +
                "        <!-- MySQL Driver -->\n" +
                "        <dependency>\n" +
                "            <groupId>mysql</groupId>\n" +
                "            <artifactId>mysql-connector-java</artifactId>\n" +
                "            <version>8.0.33</version>\n" +
                "        </dependency>\n\n" +
                "        <!-- Lombok -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.projectlombok</groupId>\n" +
                "            <artifactId>lombok</artifactId>\n" +
                "            <optional>true</optional>\n" +
                "        </dependency>\n\n" +
                "        <!-- Swagger -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springdoc</groupId>\n" +
                "            <artifactId>springdoc-openapi-ui</artifactId>\n" +
                "            <version>1.7.0</version>\n" +
                "        </dependency>\n\n" +
                "        <!-- Spring Boot Test -->\n" +
                "        <dependency>\n" +
                "            <groupId>org.springframework.boot</groupId>\n" +
                "            <artifactId>spring-boot-starter-test</artifactId>\n" +
                "            <scope>test</scope>\n" +
                "        </dependency>\n\n" +
                "        <!-- H2 Database for Testing -->\n" +
                "        <dependency>\n" +
                "            <groupId>com.h2database</groupId>\n" +
                "            <artifactId>h2</artifactId>\n" +
                "            <scope>test</scope>\n" +
                "        </dependency>\n" +
                "    </dependencies>\n\n" +
                "    <build>\n" +
                "        <plugins>\n" +
                "            <plugin>\n" +
                "                <groupId>org.springframework.boot</groupId>\n" +
                "                <artifactId>spring-boot-maven-plugin</artifactId>\n" +
                "                <configuration>\n" +
                "                    <excludes>\n" +
                "                        <exclude>\n" +
                "                            <groupId>org.projectlombok</groupId>\n" +
                "                            <artifactId>lombok</artifactId>\n" +
                "                        </exclude>\n" +
                "                    </excludes>\n" +
                "                </configuration>\n" +
                "            </plugin>\n\n" +
                "            <!-- Maven Compiler Plugin -->\n" +
                "            <plugin>\n" +
                "                <groupId>org.apache.maven.plugins</groupId>\n" +
                "                <artifactId>maven-compiler-plugin</artifactId>\n" +
                "                <version>3.11.0</version>\n" +
                "                <configuration>\n" +
                "                    <source>8</source>\n" +
                "                    <target>8</target>\n" +
                "                </configuration>\n" +
                "            </plugin>\n" +
                "        </plugins>\n" +
                "    </build>\n\n" +
                "    <repositories>\n" +
                "        <repository>\n" +
                "            <id>maven.aliyun.com</id>\n" +
                "            <name>阿里云Maven仓库</name>\n" +
                "            <url>https://maven.aliyun.com/repository/public</url>\n" +
                "        </repository>\n" +
                "    </repositories>\n" +
                "</project>\n";
    }
    
    /**
     * 生成多表项目的README内容
     */
    private String generateMultiTableReadmeContent(List<TableMetadata> tableMetadataList, String packagePrefix) {
        StringBuilder readme = new StringBuilder();
        readme.append("# 多表 CRUD代码\n\n");
        readme.append("## 项目信息\n");
        readme.append("- **表数量**: ").append(tableMetadataList.size()).append("\n");
        readme.append("- **包名**: ").append(packagePrefix != null ? packagePrefix : "com.example").append("\n");
        readme.append("- **生成时间**: ").append(java.time.LocalDateTime.now().toString()).append("\n\n");
        
        readme.append("## 表信息\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("### ").append(entityName).append("\n");
            readme.append("- **表名**: ").append(tableMetadata.getTableName()).append("\n");
            readme.append("- **字段数量**: ").append(tableMetadata.getColumns().size()).append("\n");
            readme.append("- **主键**: ").append(tableMetadata.getPrimaryKey() != null ? tableMetadata.getPrimaryKey() : "无").append("\n\n");
        }
        
        readme.append("## 文件结构\n");
        readme.append("```\n");
        readme.append("├── pom.xml\n");
        readme.append("├── README.md\n");
        readme.append("└── src/\n");
        readme.append("    └── main/\n");
        readme.append("        ├── java/\n");
        String packagePath = (packagePrefix != null ? packagePrefix : "com.example").replace(".", "/");
        readme.append("        |   └── ").append(packagePath).append("/\n");
        readme.append("        |       ├── MultiTableApplication.java\n");
        readme.append("        |       ├── entity/\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("        |       |   ├── ").append(entityName).append(".java\n");
        }
        readme.append("        |       ├── mapper/\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("        |       |   ├── ").append(entityName).append("Mapper.java\n");
        }
        readme.append("        |       ├── service/\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("        |       |   ├── ").append(entityName).append("Service.java\n");
        }
        readme.append("        |       └── controller/\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("        |           ├── ").append(entityName).append("Controller.java\n");
        }
        readme.append("        └── resources/\n");
        readme.append("            └── application.yml\n");
        readme.append("```\n\n");
        
        readme.append("## 使用说明\n");
        readme.append("### 1. 环境要求\n");
        readme.append("- Java 8+\n");
        readme.append("- Maven 3.6+\n");
        readme.append("- MySQL 5.7+\n\n");
        readme.append("### 2. 数据库准备\n");
        readme.append("创建数据库并执行相应的CREATE TABLE语句\n\n");
        readme.append("### 3. 配置修改\n");
        readme.append("根据实际情况修改 `src/main/resources/application.yml` 中的数据库连接信息\n\n");
        readme.append("### 4. 运行项目\n");
        readme.append("```bash\n");
        readme.append("# 编译项目\n");
        readme.append("mvn clean compile\n\n");
        readme.append("# 运行项目\n");
        readme.append("mvn spring-boot:run\n");
        readme.append("```\n\n");
        readme.append("### 5. 访问应用\n");
        readme.append("- 应用地址：http://localhost:8080\n");
        readme.append("- API文档：http://localhost:8080/swagger-ui.html\n\n");
        
        readme.append("## API接口\n");
        for (TableMetadata tableMetadata : tableMetadataList) {
            String tableName = tableMetadata.getTableName().toLowerCase();
            String entityName = toPascalCase(tableMetadata.getTableName());
            readme.append("### ").append(entityName).append(" API\n");
            readme.append("- `POST /api/").append(tableName).append("` - 创建记录\n");
            readme.append("- `GET /api/").append(tableName).append("/{id}` - 根据ID查询\n");
            readme.append("- `GET /api/").append(tableName).append("` - 查询所有记录\n");
            readme.append("- `GET /api/").append(tableName).append("/page` - 分页查询\n");
            readme.append("- `PUT /api/").append(tableName).append("/{id}` - 更新记录\n");
            readme.append("- `DELETE /api/").append(tableName).append("/{id}` - 删除记录\n\n");
        }
        
        readme.append("---\n");
        readme.append("*此代码由 CRUD Generator 自动生成*\n");
        
        return readme.toString();
    }
    
    /**
     * Validate SQL safety
     */
    private void validateSqlSafety(String ddl) {
        if (ddl == null || ddl.trim().isEmpty()) {
            throw new IllegalArgumentException("SQL语句不能为空");
        }
        
        String upperDdl = ddl.toUpperCase();
        
        // Check if it contains CREATE TABLE statements
        if (!upperDdl.contains("CREATE TABLE")) {
            throw new IllegalArgumentException("必须包含CREATE TABLE语句");
        }
        
        // Check for allowed statements (DDL statements and comments)
        String[] statements = ddl.split(";");
        for (String statement : statements) {
            String trimmedStatement = statement.trim().toUpperCase();
            if (!trimmedStatement.isEmpty() && 
                !trimmedStatement.startsWith("CREATE TABLE") && 
                !trimmedStatement.startsWith("CREATE INDEX") &&
                !trimmedStatement.startsWith("CREATE DATABASE") &&
                !trimmedStatement.startsWith("CREATE SCHEMA") &&
                !trimmedStatement.startsWith("USE ") &&
                !trimmedStatement.startsWith("ALTER TABLE") &&
                !trimmedStatement.startsWith("--") &&
                !trimmedStatement.startsWith("/*")) {
                
                // 检查是否为空语句或只有空白符
                if (!trimmedStatement.matches("^\\s*$")) {
                    throw new IllegalArgumentException("不支持的SQL语句类型: " + 
                        (trimmedStatement.length() > 50 ? trimmedStatement.substring(0, 50) + "..." : trimmedStatement));
                }
            }
        }
        
        // Check dangerous keywords with context awareness
        for (String keyword : DANGEROUS_KEYWORDS) {
            if (upperDdl.contains(keyword)) {
                // Special handling for UPDATE keyword
                if ("UPDATE".equals(keyword)) {
                    // 更精确的检查：只允许在"ON UPDATE"上下文中使用UPDATE
                    // 使用正则表达式检查UPDATE是否只出现在ON UPDATE CURRENT_TIMESTAMP等合法场景中
                    if (isValidUpdateUsage(upperDdl)) {
                        continue; // 合法的UPDATE使用
                    }
                }
                // Special handling for DELETE keyword
                else if ("DELETE".equals(keyword)) {
                    // 只允许在"ON DELETE"上下文中使用DELETE
                    if (isValidDeleteUsage(upperDdl)) {
                        continue; // 合法的DELETE使用
                    }
                }
                // Special handling for ALTER keyword
                else if ("ALTER".equals(keyword)) {
                    // 只允许ALTER TABLE等DDL语句
                    if (isValidAlterUsage(upperDdl)) {
                        continue; // 合法的ALTER使用
                    }
                }
                throw new IllegalArgumentException("包含不安全的SQL关键字: " + keyword);
            }
        }
        
        // Check SQL length
        if (ddl.length() > 50000) {
            throw new IllegalArgumentException("SQL语句长度超过限制");
        }
    }
    
    /**
     * 检查UPDATE关键字的使用是否合法
     * 只允许在"ON UPDATE"上下文中使用UPDATE关键字
     * 
     * @param upperDdl 大写的DDL语句
     * @return true如果UPDATE使用合法，false如果有安全风险
     */
    private boolean isValidUpdateUsage(String upperDdl) {
        // 使用正则表达式找到所有UPDATE关键字的位置
        java.util.regex.Pattern updatePattern = java.util.regex.Pattern.compile("\\bUPDATE\\b");
        java.util.regex.Matcher matcher = updatePattern.matcher(upperDdl);
        
        while (matcher.find()) {
            int updatePos = matcher.start();
            
            // 检查UPDATE前面是否紧跟着"ON "
            boolean isOnUpdate = false;
            if (updatePos >= 3) {
                String beforeUpdate = upperDdl.substring(Math.max(0, updatePos - 10), updatePos).trim();
                if (beforeUpdate.endsWith("ON")) {
                    isOnUpdate = true;
                }
            }
            
            // 如果不是"ON UPDATE"模式，则不安全
            if (!isOnUpdate) {
                log.warn("发现可疑的UPDATE关键字使用，位置: {}", updatePos);
                return false;
            }
            
            // 进一步检查ON UPDATE后面是否跟着合法的值
            String afterUpdate = upperDdl.substring(updatePos + 6).trim();
            if (!afterUpdate.startsWith("CURRENT_TIMESTAMP") && 
                !afterUpdate.startsWith("NOW()") && 
                !afterUpdate.startsWith("LOCALTIME") &&
                !afterUpdate.startsWith("LOCALTIMESTAMP")) {
                log.warn("ON UPDATE后面跟着非法内容: {}", afterUpdate.substring(0, Math.min(20, afterUpdate.length())));
                return false;
            }
        }
        
        return true;
    }

    private GenerationOptions buildGenerationOptions(Boolean enableSecurity, Boolean enableRedis) {
        return GenerationOptions.builder()
            .enableSecurity(Boolean.TRUE.equals(enableSecurity))
            .enableRedis(Boolean.TRUE.equals(enableRedis))
            .build();
    }
    
    /**
     * 检查DELETE关键字的使用是否合法
     * 只允许在"ON DELETE"上下文中使用DELETE关键字
     * 
     * @param upperDdl 大写的DDL语句
     * @return true如果DELETE使用合法，false如果有安全风险
     */
    private boolean isValidDeleteUsage(String upperDdl) {
        // 使用正则表达式找到所有DELETE关键字的位置
        java.util.regex.Pattern deletePattern = java.util.regex.Pattern.compile("\\bDELETE\\b");
        java.util.regex.Matcher matcher = deletePattern.matcher(upperDdl);
        
        while (matcher.find()) {
            int deletePos = matcher.start();
            
            // 检查DELETE前面是否紧跟着"ON "
            boolean isOnDelete = false;
            if (deletePos >= 3) {
                String beforeDelete = upperDdl.substring(Math.max(0, deletePos - 10), deletePos).trim();
                if (beforeDelete.endsWith("ON")) {
                    isOnDelete = true;
                }
            }
            
            // 如果不是"ON DELETE"模式，则不安全
            if (!isOnDelete) {
                log.warn("发现可疑的DELETE关键字使用，位置: {}", deletePos);
                return false;
            }
            
            // 进一步检查ON DELETE后面是否跟着合法的外键动作
            String afterDelete = upperDdl.substring(deletePos + 6).trim();
            if (!afterDelete.startsWith("CASCADE") && 
                !afterDelete.startsWith("RESTRICT") && 
                !afterDelete.startsWith("SET NULL") &&
                !afterDelete.startsWith("SET DEFAULT") &&
                !afterDelete.startsWith("NO ACTION")) {
                log.warn("ON DELETE后面跟着非法内容: {}", afterDelete.substring(0, Math.min(20, afterDelete.length())));
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 检查ALTER关键字的使用是否合法
     * 只允许DDL语句中的ALTER TABLE等合法用法
     * 
     * @param upperDdl 大写的DDL语句
     * @return true如果ALTER使用合法，false如果有安全风险
     */
    private boolean isValidAlterUsage(String upperDdl) {
        // 使用正则表达式找到所有ALTER关键字的位置
        java.util.regex.Pattern alterPattern = java.util.regex.Pattern.compile("\\bALTER\\b");
        java.util.regex.Matcher matcher = alterPattern.matcher(upperDdl);
        
        while (matcher.find()) {
            int alterPos = matcher.start();
            
            // 检查ALTER后面跟着的是否为合法的DDL操作
            String afterAlter = upperDdl.substring(alterPos + 5).trim();
            
            // 只允许以下ALTER操作
            if (afterAlter.startsWith("TABLE") ||
                afterAlter.startsWith("DATABASE") ||
                afterAlter.startsWith("SCHEMA") ||
                afterAlter.startsWith("INDEX")) {
                
                log.debug("检测到合法的ALTER语句: ALTER {}", 
                    afterAlter.substring(0, Math.min(20, afterAlter.length())));
                continue; // 合法的ALTER使用
            } else {
                log.warn("发现可疑的ALTER关键字使用，位置: {}, 后续内容: {}", 
                    alterPos, afterAlter.substring(0, Math.min(50, afterAlter.length())));
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * 验证请求参数的合法性
     * 
     * @param request 请求参数
     */
    private void validateRequest(SqlParseRequest request) {
        // 验证包名格式
        if (request.getPackagePrefix() != null && !request.getPackagePrefix().trim().isEmpty()) {
            String packageName = request.getPackagePrefix().trim();
            if (!isValidPackageName(packageName)) {
                throw new IllegalArgumentException("包名格式不正确。包名应该符合Java命名规范，如：com.example.project");
            }
        }
        
        // 验证作者名格式
        if (request.getAuthor() != null && !request.getAuthor().trim().isEmpty()) {
            String author = request.getAuthor().trim();
            if (!isValidAuthorName(author)) {
                throw new IllegalArgumentException("作者名格式不正确。作者名长度应在1-50字符之间，不能包含特殊字符");
            }
        }
    }
    
    /**
     * 验证包名是否符合Java命名规范
     * 
     * @param packageName 包名
     * @return true如果格式正确
     */
    private boolean isValidPackageName(String packageName) {
        if (packageName == null || packageName.trim().isEmpty()) {
            return false;
        }
        
        // Java包名规则：
        // 1. 只能包含字母、数字、下划线和点号
        // 2. 不能以数字开头
        // 3. 不能以点号开头或结尾
        // 4. 不能包含连续的点号
        String regex = "^[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)*$";
        if (!packageName.matches(regex)) {
            return false;
        }
        
        // 检查是否包含Java关键字
        String[] parts = packageName.split("\\.");
        for (String part : parts) {
            if (isJavaKeyword(part)) {
                return false;
            }
        }
        
        // 包名长度限制
        if (packageName.length() > 200) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 验证作者名是否符合规范
     * 
     * @param author 作者名
     * @return true如果格式正确
     */
    private boolean isValidAuthorName(String author) {
        if (author == null || author.trim().isEmpty()) {
            return false;
        }
        
        String trimmedAuthor = author.trim();
        
        // 长度检查
        if (trimmedAuthor.length() > 50 || trimmedAuthor.length() < 1) {
            return false;
        }
        
        // 不允许包含控制字符和某些特殊字符
        String regex = "^[\\w\\s\\u4e00-\\u9fa5.-]*$";
        if (!trimmedAuthor.matches(regex)) {
            return false;
        }
        
        // 不允许只包含空格
        if (trimmedAuthor.matches("^\\s+$")) {
            return false;
        }
        
        return true;
    }
    
    /**
     * 检查是否为Java关键字
     * 
     * @param word 待检查的单词
     * @return true如果是Java关键字
     */
    private boolean isJavaKeyword(String word) {
        String[] keywords = {
            "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
            "class", "const", "continue", "default", "do", "double", "else", "enum",
            "extends", "final", "finally", "float", "for", "goto", "if", "implements",
            "import", "instanceof", "int", "interface", "long", "native", "new", "package",
            "private", "protected", "public", "return", "short", "static", "strictfp",
            "super", "switch", "synchronized", "this", "throw", "throws", "transient",
            "try", "void", "volatile", "while", "true", "false", "null"
        };
        
        return java.util.Arrays.asList(keywords).contains(word.toLowerCase());
    }
    
    /**
     * 获取数据库表列表
     */
    @PostMapping("/database/tables")
    @Operation(
        summary = "获取数据库表列表",
        description = "连接到MySQL数据库并获取所有表名"
    )
    public ResponseEntity<ApiResponse<List<String>>> getDatabaseTables(
            @Parameter(description = "数据库连接请求") @RequestBody @Valid DatabaseConnectionRequest request) {
        
        log.info("收到获取数据库表列表请求: {}:{}/{}", request.getHost(), request.getPort(), request.getDatabase());
        
        try {
            // 验证数据库连接参数
            validateDatabaseConnection(request);
            
            List<String> tableNames = databaseReverseService.getTableNames(
                request.getHost(), request.getPort(), request.getDatabase(),
                request.getUsername(), request.getPassword()
            );
            
            return ResponseEntity.ok(ApiResponse.success(tableNames));
            
        } catch (Exception e) {
            log.error("获取数据库表列表失败", e);
            return ResponseEntity.badRequest().body(ApiResponse.error(400, "获取表列表失败: " + e.getMessage()));
        }
    }
    
    /**
     * 从数据库读取表结构并生成DDL
     */
    @PostMapping("/database/reverse")
    @Operation(
        summary = "从数据库逆向生成DDL",
        description = "连接到MySQL数据库，读取指定表的结构并生成CREATE TABLE语句"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> reverseFromDatabase(
            @Parameter(description = "数据库连接请求") @RequestBody @Valid DatabaseConnectionRequest request) {
        
        log.info("收到数据库逆向工程请求: 表{}", request.getTableName());
        
        try {
            // 验证数据库连接参数
            validateDatabaseConnection(request);
            
            if (request.getTableName() == null || request.getTableName().trim().isEmpty()) {
                throw new IllegalArgumentException("表名不能为空");
            }
            
            // 从数据库读取表结构
            TableMetadata tableMetadata = databaseReverseService.readTableStructure(
                request.getHost(), request.getPort(), request.getDatabase(),
                request.getUsername(), request.getPassword(), request.getTableName()
            );
            
            // 生成DDL语句
            String ddl = generateDDLFromMetadata(tableMetadata);
            
            Map<String, Object> result = new HashMap<>();
            result.put("tableName", tableMetadata.getTableName());
            result.put("tableComment", tableMetadata.getTableComment());
            result.put("columnCount", tableMetadata.getColumns().size());
            result.put("ddl", ddl);
            result.put("metadata", tableMetadata);
            
            return ResponseEntity.ok(ApiResponse.success(result));
            
        } catch (Exception e) {
            log.error("数据库逆向工程失败", e);
            return ResponseEntity.badRequest().body(ApiResponse.error(400, "逆向工程失败: " + e.getMessage()));
        }
    }
    
    /**
     * 从数据库直接生成代码
     */
    @PostMapping("/database/generate")
    @Operation(
        summary = "从数据库直接生成代码",
        description = "连接到MySQL数据库，读取指定表的结构并直接生成CRUD代码"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> generateFromDatabase(
            @Parameter(description = "数据库连接请求") @RequestBody @Valid DatabaseConnectionRequest request) {
        
        log.info("收到从数据库直接生成代码请求: 表{}", request.getTableName());
        
        try {
            // 验证数据库连接参数和额外参数
            validateDatabaseConnection(request);
            validateDatabaseGenerationRequest(request);
            
            // 从数据库读取表结构
            TableMetadata tableMetadata = databaseReverseService.readTableStructure(
                request.getHost(), request.getPort(), request.getDatabase(),
                request.getUsername(), request.getPassword(), request.getTableName()
            );
            
            // 生成代码
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            crudGenerator.generateAll(tableMetadata, options);

            Map<String, Object> result = new HashMap<>();
            result.put("tableName", tableMetadata.getTableName());
            result.put("tableComment", tableMetadata.getTableComment());
            result.put("columnCount", tableMetadata.getColumns().size());
            result.put("packagePrefix", request.getPackagePrefix());
            result.put("author", request.getAuthor());
            result.put("enableSecurity", Boolean.TRUE.equals(request.getEnableSecurity()));
            result.put("enableRedis", Boolean.TRUE.equals(request.getEnableRedis()));
            result.put("message", "代码生成完成");
            
            return ResponseEntity.ok(ApiResponse.success(result));
            
        } catch (Exception e) {
            log.error("从数据库生成代码失败", e);
            return ResponseEntity.badRequest().body(ApiResponse.error(400, "生成代码失败: " + e.getMessage()));
        }
    }
    
    /**
     * 验证数据库连接参数
     */
    private void validateDatabaseConnection(DatabaseConnectionRequest request) {
        if (request.getHost() == null || request.getHost().trim().isEmpty()) {
            throw new IllegalArgumentException("数据库主机不能为空");
        }
        
        if (request.getPort() == null || request.getPort() <= 0 || request.getPort() > 65535) {
            throw new IllegalArgumentException("数据库端口必须在1-65535之间");
        }
        
        if (request.getDatabase() == null || request.getDatabase().trim().isEmpty()) {
            throw new IllegalArgumentException("数据库名不能为空");
        }
        
        if (request.getUsername() == null || request.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        // 安全检查：防止SQL注入
        String[] inputs = {request.getHost(), request.getDatabase(), request.getUsername(), request.getTableName()};
        for (String input : inputs) {
            if (input != null && (input.contains("'") || input.contains("\"") || input.contains(";") || input.contains("--"))) {
                throw new IllegalArgumentException("参数包含不安全字符");
            }
        }
    }
    
    /**
     * 验证批量数据库请求的连接参数
     */
    private void validateBatchDatabaseConnection(BatchDatabaseRequest request) {
        if (request.getHost() == null || request.getHost().trim().isEmpty()) {
            throw new IllegalArgumentException("数据库主机不能为空");
        }
        
        if (request.getPort() == null || request.getPort() <= 0 || request.getPort() > 65535) {
            throw new IllegalArgumentException("数据库端口必须在1-65535之间");
        }
        
        if (request.getDatabase() == null || request.getDatabase().trim().isEmpty()) {
            throw new IllegalArgumentException("数据库名不能为空");
        }
        
        if (request.getUsername() == null || request.getUsername().trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        
        // 安全检查：防止SQL注入
        String[] inputs = {request.getHost(), request.getDatabase(), request.getUsername()};
        for (String input : inputs) {
            if (input != null && (input.contains("'") || input.contains("\"") || input.contains(";") || input.contains("--"))) {
                throw new IllegalArgumentException("参数包含不安全字符");
            }
        }
        
        // 验证表名列表中的每个表名
        if (request.getTableNames() != null) {
            for (String tableName : request.getTableNames()) {
                if (tableName != null && (tableName.contains("'") || tableName.contains("\"") || tableName.contains(";") || tableName.contains("--"))) {
                    throw new IllegalArgumentException("表名包含不安全字符: " + tableName);
                }
            }
        }
    }
    
    /**
     * 验证数据库代码生成请求的额外参数
     */
    private void validateDatabaseGenerationRequest(DatabaseConnectionRequest request) {
        if (request.getTableName() == null || request.getTableName().trim().isEmpty()) {
            throw new IllegalArgumentException("表名不能为空");
        }
        
        // 验证包名格式
        if (request.getPackagePrefix() != null && !request.getPackagePrefix().trim().isEmpty()) {
            if (!isValidPackageName(request.getPackagePrefix().trim())) {
                throw new IllegalArgumentException("包名格式不正确。包名应该符合Java命名规范，如：com.example.project");
            }
        }
        
        // 验证作者名格式
        if (request.getAuthor() != null && !request.getAuthor().trim().isEmpty()) {
            if (!isValidAuthorName(request.getAuthor().trim())) {
                throw new IllegalArgumentException("作者名格式不正确。作者名长度应在1-50字符之间，不能包含特殊字符");
            }
        }
    }
    
    /**
     * 从表元数据生成DDL语句
     */
    private String generateDDLFromMetadata(TableMetadata metadata) {
        StringBuilder ddl = new StringBuilder();
        ddl.append("CREATE TABLE ").append(metadata.getTableName()).append(" (\n");
        
        List<ColumnMetadata> columns = metadata.getColumns();
        for (int i = 0; i < columns.size(); i++) {
            ColumnMetadata column = columns.get(i);
            ddl.append("    ").append(column.getColumnName());
            ddl.append(" ").append(column.getDataType());
            
            // 添加长度信息
            if (column.getLength() != null && column.getLength() > 0) {
                ddl.append("(").append(column.getLength());
                if (column.getScale() != null && column.getScale() > 0) {
                    ddl.append(",").append(column.getScale());
                }
                ddl.append(")");
            }
            
            // 添加约束
            if (column.getPrimaryKey()) {
                ddl.append(" PRIMARY KEY");
            }
            
            if (column.getAutoIncrement()) {
                ddl.append(" AUTO_INCREMENT");
            }
            
            if (!column.getNullable()) {
                ddl.append(" NOT NULL");
            }
            
            if (column.getDefaultValue() != null && !column.getDefaultValue().isEmpty()) {
                ddl.append(" DEFAULT ").append(column.getDefaultValue());
            }
            
            if (column.getColumnComment() != null && !column.getColumnComment().isEmpty()) {
                ddl.append(" COMMENT '").append(column.getColumnComment()).append("'");
            }
            
            if (i < columns.size() - 1) {
                ddl.append(",");
            }
            ddl.append("\n");
        }
        
        ddl.append(")");
        
        if (metadata.getTableComment() != null && !metadata.getTableComment().isEmpty()) {
            ddl.append(" COMMENT '").append(metadata.getTableComment()).append("'");
        }
        
        ddl.append(";");
        
        return ddl.toString();
    }
    
    /**
     * 批量生成代码
     */
    @PostMapping("/batch/generate")
    @Operation(
        summary = "批量生成代码",
        description = "批量处理多个CREATE TABLE语句，同时生成多个表的CRUD代码"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> batchGenerate(
            @Parameter(description = "批量生成请求") @RequestBody @Valid BatchGenerationRequest request) {
        
        log.info("收到批量生成代码请求，表数量: {}", request.getDdlList().size());
        
        try {
            // 验证批量请求参数
            validateBatchRequest(request);
            
            Map<String, Object> results = new HashMap<>();
            List<Map<String, Object>> successTables = new ArrayList<>();
            List<Map<String, Object>> failedTables = new ArrayList<>();
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            
            int processedCount = 0;
            for (String ddl : request.getDdlList()) {
                processedCount++;
                
                try {
                    log.info("处理第{}个表的DDL", processedCount);
                    
                    // SQL安全检查
                    validateSqlSafety(ddl);
                    
                    // 解析表结构
                    TableMetadata tableMetadata = sqlDdlParser.parseCreateTable(ddl.trim());
                    
                    Map<String, Object> tableResult = new HashMap<>();
                    tableResult.put("tableName", tableMetadata.getTableName());
                    tableResult.put("tableComment", tableMetadata.getTableComment());
                    tableResult.put("columnCount", tableMetadata.getColumns().size());
                    
                    if (request.getGenerateFiles()) {
                        // 生成代码文件
                        crudGenerator.generateAll(tableMetadata, options);
                        tableResult.put("status", "generated");
                        tableResult.put("message", "代码生成完成");
                    } else {
                        // 只预览代码
                        Map<String, String> preview = crudGenerator.previewAll(tableMetadata, options);
                        tableResult.put("status", "previewed");
                        tableResult.put("preview", preview);
                        tableResult.put("message", "代码预览完成");
                    }
                    
                    successTables.add(tableResult);
                    
                } catch (Exception e) {
                    log.error("处理第{}个表失败: {}", processedCount, e.getMessage());
                    
                    Map<String, Object> errorResult = new HashMap<>();
                    errorResult.put("index", processedCount);
                    errorResult.put("ddl", ddl.length() > 100 ? ddl.substring(0, 100) + "..." : ddl);
                    errorResult.put("error", e.getMessage());
                    failedTables.add(errorResult);
                }
            }
            
            results.put("totalCount", request.getDdlList().size());
            results.put("successCount", successTables.size());
            results.put("failedCount", failedTables.size());
            results.put("successTables", successTables);
            results.put("failedTables", failedTables);
            results.put("packagePrefix", request.getPackagePrefix());
            results.put("author", request.getAuthor());
            results.put("generateFiles", request.getGenerateFiles());
            
            return ResponseEntity.ok(ApiResponse.success(results));
            
        } catch (Exception e) {
            log.error("批量生成代码失败", e);
            return ResponseEntity.badRequest().body(ApiResponse.error(400, "批量生成失败: " + e.getMessage()));
        }
    }
    
    /**
     * 批量从数据库生成代码
     * 
     * @param request 包含数据库连接信息和表名列表的请求
     */
    @PostMapping("/batch/database-generate")
    @Operation(
        summary = "批量从数据库生成代码",
        description = "连接到数据库，批量读取多个表的结构并生成CRUD代码"
    )
    public ResponseEntity<ApiResponse<Map<String, Object>>> batchGenerateFromDatabase(
            @Parameter(description = "批量数据库生成请求") @RequestBody @Valid BatchDatabaseRequest request) {
        
        log.info("收到批量从数据库生成代码请求，表数量: {}", request.getTableNames().size());
        
        try {
            // 验证数据库连接参数
            validateBatchDatabaseConnection(request);
            validateBatchDatabaseRequest(request);
            
            Map<String, Object> results = new HashMap<>();
            List<Map<String, Object>> successTables = new ArrayList<>();
            List<Map<String, Object>> failedTables = new ArrayList<>();
            GenerationOptions options = buildGenerationOptions(request.getEnableSecurity(), request.getEnableRedis());
            
            int processedCount = 0;
            for (String tableName : request.getTableNames()) {
                processedCount++;
                
                try {
                    log.info("处理第{}个表: {}", processedCount, tableName);
                    
                    // 从数据库读取表结构
                    TableMetadata tableMetadata = databaseReverseService.readTableStructure(
                        request.getHost(), request.getPort(), request.getDatabase(),
                        request.getUsername(), request.getPassword(), tableName
                    );
                    
                    Map<String, Object> tableResult = new HashMap<>();
                    tableResult.put("tableName", tableMetadata.getTableName());
                    tableResult.put("tableComment", tableMetadata.getTableComment());
                    tableResult.put("columnCount", tableMetadata.getColumns().size());
                    
                    if (request.getGenerateFiles()) {
                        // 生成代码文件
                        crudGenerator.generateAll(tableMetadata, options);
                        tableResult.put("status", "generated");
                        tableResult.put("message", "代码生成完成");
                    } else {
                        // 只预览代码
                        Map<String, String> preview = crudGenerator.previewAll(tableMetadata, options);
                        tableResult.put("status", "previewed");
                        tableResult.put("preview", preview);
                        tableResult.put("message", "代码预览完成");
                    }
                    
                    successTables.add(tableResult);
                    
                } catch (Exception e) {
                    log.error("处理表{}失败: {}", tableName, e.getMessage());
                    
                    Map<String, Object> errorResult = new HashMap<>();
                    errorResult.put("tableName", tableName);
                    errorResult.put("error", e.getMessage());
                    failedTables.add(errorResult);
                }
            }
            
            results.put("totalCount", request.getTableNames().size());
            results.put("successCount", successTables.size());
            results.put("failedCount", failedTables.size());
            results.put("successTables", successTables);
            results.put("failedTables", failedTables);
            results.put("packagePrefix", request.getPackagePrefix());
            results.put("author", request.getAuthor());
            results.put("generateFiles", request.getGenerateFiles());
            
            return ResponseEntity.ok(ApiResponse.success(results));
            
        } catch (Exception e) {
            log.error("批量从数据库生成代码失败", e);
            return ResponseEntity.badRequest().body(ApiResponse.error(400, "批量生成失败: " + e.getMessage()));
        }
    }
    
    /**
     * 验证批量请求参数
     */
    private void validateBatchRequest(BatchGenerationRequest request) {
        if (request.getDdlList() == null || request.getDdlList().isEmpty()) {
            throw new IllegalArgumentException("DDL语句列表不能为空");
        }
        
        if (request.getDdlList().size() > 10) {
            throw new IllegalArgumentException("一次最多处理10个表");
        }
        
        // 验证包名格式
        if (request.getPackagePrefix() != null && !request.getPackagePrefix().trim().isEmpty()) {
            if (!isValidPackageName(request.getPackagePrefix().trim())) {
                throw new IllegalArgumentException("包名格式不正确。包名应该符合Java命名规范，如：com.example.project");
            }
        }
        
        // 验证作者名格式
        if (request.getAuthor() != null && !request.getAuthor().trim().isEmpty()) {
            if (!isValidAuthorName(request.getAuthor().trim())) {
                throw new IllegalArgumentException("作者名格式不正确。作者名长度应在1-50字符之间，不能包含特殊字符");
            }
        }
        
        // 验证每个DDL语句
        for (String ddl : request.getDdlList()) {
            if (ddl == null || ddl.trim().isEmpty()) {
                throw new IllegalArgumentException("DDL语句不能为空");
            }
            if (ddl.length() > 10000) {
                throw new IllegalArgumentException("DDL语句长度不能超过10000字符");
            }
        }
    }
    
    /**
     * 验证批量数据库请求参数
     */
    private void validateBatchDatabaseRequest(BatchDatabaseRequest request) {
        if (request.getTableNames() == null || request.getTableNames().isEmpty()) {
            throw new IllegalArgumentException("表名列表不能为空");
        }
        
        if (request.getTableNames().size() > 10) {
            throw new IllegalArgumentException("一次最多处理10个表");
        }
        
        // 验证包名格式
        if (request.getPackagePrefix() != null && !request.getPackagePrefix().trim().isEmpty()) {
            if (!isValidPackageName(request.getPackagePrefix().trim())) {
                throw new IllegalArgumentException("包名格式不正确。包名应该符合Java命名规范，如：com.example.project");
            }
        }
        
        // 验证作者名格式
        if (request.getAuthor() != null && !request.getAuthor().trim().isEmpty()) {
            if (!isValidAuthorName(request.getAuthor().trim())) {
                throw new IllegalArgumentException("作者名格式不正确。作者名长度应在1-50字符之间，不能包含特殊字符");
            }
        }
    }
}
